/*
 * _______________#########_______________________ 
 * ______________############_____________________ 
 * ______________#############____________________ 
 * _____________##__###########___________________ 
 * ____________###__######_#####__________________ 
 * ____________###_#######___####_________________ 
 * ___________###__##########_####________________ 
 * __________####__###########_####_______________ 
 * ________#####___###########__#####_____________ 
 * _______######___###_########___#####___________ 
 * _______#####___###___########___######_________ 
 * ______######___###__###########___######_______ 
 * _____######___####_##############__######______ 
 * ____#######__#####################_#######_____ 
 * ____#######__##############################____ 
 * ___#######__######_#################_#######___ 
 * ___#######__######_######_#########___######___ 
 * ___#######____##__######___######_____######___ 
 * ___#######________######____#####_____#####____ 
 * ____######________#####_____#####_____####_____ 
 * _____#####________####______#####_____###______ 
 * ______#####______;###________###______#________ 
 * ________##_______####________####______________ 
 * 
 * @Author: ipk518 18163976442@163.com
 * @Date: 2024-09-03 11:41:28
 * @LastEditors: ipk518 18163976442@163.com
 * @LastEditTime: 2024-09-13 17:31:03
 * @FilePath: /tools/qsfp/qsfp.c
 * @Description: 
 * ************佛祖保佑************
 * Copyright (c) 2024 by etws@quyujiang, All Rights Reserved. 
 */

#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>

#include "qsfp.h"

int m_qsfp_4x_fd = -1;
int m_qsfp_12x_fd = -1;

uint8_t m_qsfp_4x_upper[QSFP_PAGENUM_4X][QSFP_PAGEUPPER];
uint8_t m_qsfp_12x_tx_upper[QSFP_PAGENUM_12X][QSFP_PAGEUPPER];
uint8_t m_qsfp_12x_rx_upper[QSFP_PAGENUM_12X][QSFP_PAGEUPPER];


static int qsfp_init(const char *devName)
{
    int fd = 0;

    //打开IIC总线设备节点
    // fd = open(reinterpret_cast<const char*>(dev_path), O_RDWR);
    fd = open(devName, O_RDWR);
    return fd;
}


static int refresh_qsfp_cache(int fd, uint8_t addr, uint8_t reg, uint8_t *buffer, int len)
{
    if (fd < 0) {
        return -1;
    }
    int ret = -1;
    int regAddr = reg;
    unsigned char dataBuff[QSFP_PAGESIZE] = { 0 };
    unsigned short dataLen = QSFP_PAGESIZE;
    //读数据有2个msg
    struct i2c_msg msg[2] = {
        {
            .addr = addr,   //设备地址
            .flags = 0,         //标志，为0表示写数据
            .len = 1,           //要写的数据的长度
            .buf = (__u8 *)&regAddr,   //要写的数据的地址
        },
        {
            .addr = addr,   //设备地址
            .flags = I2C_M_RD,  //标志，I2C_M_RD表示主机向主机读数据
            .len = dataLen,         //要读取的数据的长度
            .buf = dataBuff,        //读取的数据存放的地址
        },
    };

    struct i2c_rdwr_ioctl_data rdwr_msg = {
        .msgs = msg,
        .nmsgs = 2,
    };

    ret = ioctl(fd, I2C_RDWR, &rdwr_msg);
    if (ret < 0) {
      printf("refresh_qsfp_cache failed, errno=%d.\n", errno);
      return ret;
    }
    memcpy(buffer,dataBuff,len);
    
    return ret;
}


static int qsfp_write(int fd,uint8_t addr, uint8_t reg,uint8_t *wdata, uint8_t wlen)
{
    if (fd < 0) {
        return -1;
    }
    int ret = -1;
    unsigned char buff[20] = { 0 };
    unsigned short dataLen = (unsigned short)(wlen+1);
    buff[0] = reg;
    memcpy(&buff[1], wdata, wlen);

    //写数据是1个msg
    struct i2c_msg msg = {
        .addr = addr,
        .flags = 0,
        .len = dataLen,
        .buf = buff,
    };

    struct i2c_rdwr_ioctl_data rdwr_msg = {
        .msgs = &msg,
        .nmsgs = 1,
    };

    ret = ioctl(fd, I2C_RDWR, &rdwr_msg);

    return ret;
}


static int qsfp_read(int fd, unsigned short dev_addr,  unsigned char reg_addr, unsigned char* data, unsigned int len)
{
    int ret = -1;
    unsigned short dataLen = (unsigned short)len;
    //读数据有2个msg
    struct i2c_msg msg[2] = {
        {
            .addr = dev_addr,   //设备地址
            .flags = 0,         //标志，为0表示写数据
            .len = 1,           //要写的数据的长度
            .buf = &reg_addr,   //要写的数据的地址
        },
        {
            .addr = dev_addr,   //设备地址
            .flags = I2C_M_RD,  //标志，I2C_M_RD表示主机向主机读数据
            .len = dataLen,         //要读取的数据的长度
            .buf = data,        //读取的数据存放的地址
        },
    };

    struct i2c_rdwr_ioctl_data rdwr_msg = {
        .msgs = msg,
        .nmsgs = 2,
    };

    ret = ioctl(fd, I2C_RDWR, &rdwr_msg);

    return ret;
}

int qsfp_4x_init()
{
    m_qsfp_4x_fd = qsfp_init(X4_DEV_NAME);
    if(m_qsfp_4x_fd < 0) {
        return -1;
    }
    return 0;
}

int qsfp_12x_init()
{
    m_qsfp_12x_fd = qsfp_init(X12_DEV_NAME);
    if(m_qsfp_12x_fd < 0) {
        return -1;
    }
    return 0;
}

int refresh_qsfp_4x_cache(struct qsfp_4x_cache *cp)
{
    return refresh_qsfp_cache(m_qsfp_4x_fd,QSFP_DEV,0,(uint8_t *)cp,QSFP_PAGESIZE);
}


int refresh_qsfp_12x_tx_cache(struct qsfp_12x_Txcache *cp)
{
    return refresh_qsfp_cache(m_qsfp_12x_fd,QSFP_TX_DEV,0,(uint8_t *)cp,QSFP_PAGESIZE);
}

int refresh_qsfp_12x_rx_cache(struct qsfp_12x_Rxcache *cp)
{
    return refresh_qsfp_cache(m_qsfp_12x_fd,QSFP_RX_DEV,0,(uint8_t *)cp,QSFP_PAGESIZE);
}


int qsfp_page_4x_change(int page)
{
    return qsfp_write(m_qsfp_4x_fd,QSFP_DEV,QSFP_PAGE, (uint8_t *)&page,1);
}

int qsfp_page_12x_tx_change(int page)
{
    return qsfp_write(m_qsfp_12x_fd,QSFP_TX_DEV,QSFP_PAGE, (uint8_t *)&page,1);
}

int qsfp_page_12x_rx_change(int page)
{
    return qsfp_write(m_qsfp_12x_fd,QSFP_RX_DEV,QSFP_PAGE, (uint8_t *)&page,1);
}

void refresh_qsfp_4x_upperMemory()
{
    for(int i=0;i<QSFP_PAGENUM_4X;i++)
    {
        qsfp_page_4x_change(i);
        refresh_qsfp_cache(m_qsfp_4x_fd,QSFP_DEV,(QSFP_PAGE+1),(uint8_t *)m_qsfp_4x_upper[i],QSFP_PAGEUPPER);
    }
}

void refresh_qsfp_12x_tx_upperMemory()
{
    for(int i=0;i<QSFP_PAGENUM_12X;i++)
    {
        qsfp_page_12x_tx_change(i);
        refresh_qsfp_cache(m_qsfp_12x_fd,QSFP_TX_DEV,(QSFP_PAGE+1),(uint8_t *)m_qsfp_12x_tx_upper[i],QSFP_PAGEUPPER);
    }
}

void refresh_qsfp_12x_rx_upperMemory()
{
    for(int i=0;i<QSFP_PAGENUM_12X;i++)
    {
        qsfp_page_12x_rx_change(i);
        refresh_qsfp_cache(m_qsfp_12x_fd,QSFP_RX_DEV,(QSFP_PAGE+1),(uint8_t *)m_qsfp_12x_rx_upper[i],QSFP_PAGEUPPER);
    }
}